package com.boarsoft.boar.sequence.client;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.boar.sequence.biz.SeqNumberBiz;
import com.boarsoft.boar.sequence.biz.SeqSegmentBiz;
import com.boarsoft.boar.sequence.core.Sequence;
import com.boarsoft.boar.sequence.entity.SequenceSegment;
import com.boarsoft.boar.sequence.service.SequenceService;
import com.boarsoft.common.util.InetUtil;

/**
 * <p>
 * 方案一：允许分段发号和丢号，可分区<br>
 * 查询号段（带或不带max）但不入号码表<br>
 * 启动时从业务表取最大号（max） 在内存给最大号+1
 * </p>
 * 
 * @author Mac_J
 *
 */
public class BasicSegSeqImpl implements Sequence {
	private static final Logger log = LoggerFactory.getLogger(BasicSegSeqImpl.class);

	/** 通过XML配置注入 */
	protected SequenceService sequenceService;

	/** 序列号码表的Biz */
	protected SeqNumberBiz seqNoBiz;
	/** 序列号段表的Biz */
	protected SeqSegmentBiz seqSegBiz;

	/** */
	protected String catalog;
	/** */
	protected String code;
	/** */
	protected long beginNo;
	/** */
	protected long endNo;

	/** 总是下一次的值 */
	protected long nextNo;

	@PostConstruct
	public void init() {
		if (sequenceService == null) {
			throw new InstantiationError("Sequence service is required");
		}
		// 即使重启后IP发生变化，可能取到别的节点的号段，但这不影响结果
		this.query();
	}

	/**
	 * 根据IP从序列服务查询号段
	 */
	protected void query() {
		SequenceSegment seg = sequenceService.getSegment(catalog, code, this.tag());
		log.info("Get sequence segment {}", seg);
		this.beginNo = seg.getBeginNo();
		this.endNo = seg.getEndNo();
		// 从数据库查询此号段的最大值
		nextNo = seqSegBiz.restore(catalog, code, beginNo, endNo);
	}

	/**
	 * 返回当前节点的标签（默认用IP）
	 * 
	 * @return
	 */
	protected String tag() {
		return InetUtil.getAddr();
	}

	@Override
	public synchronized long next() {
		long no = nextNo++;
		if (no < beginNo || no > endNo) {
			this.query(); // 从序列服务查新号段
			no = nextNo++;
		}
		if (no < beginNo || no > endNo) {
			throw new IllegalStateException(String.format(//
					"Can not get next %s.%s sequence no", catalog, code));
		}
		return no;
	}

	public SequenceService getSequenceService() {
		return sequenceService;
	}

	public void setSequenceService(SequenceService sequenceService) {
		this.sequenceService = sequenceService;
	}

	public SeqNumberBiz getSeqNoBiz() {
		return seqNoBiz;
	}

	public void setSeqNoBiz(SeqNumberBiz seqNoBiz) {
		this.seqNoBiz = seqNoBiz;
	}

	public SeqSegmentBiz getSeqSegBiz() {
		return seqSegBiz;
	}

	public void setSeqSegBiz(SeqSegmentBiz seqSegBiz) {
		this.seqSegBiz = seqSegBiz;
	}

	public String getCatalog() {
		return catalog;
	}

	public void setCatalog(String catalog) {
		this.catalog = catalog;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public long getBeginNo() {
		return beginNo;
	}

	public void setBeginNo(long beginNo) {
		this.beginNo = beginNo;
	}

	public long getEndNo() {
		return endNo;
	}

	public void setEndNo(long endNo) {
		this.endNo = endNo;
	}
}